/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.dandsoft.mavrep.dao;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.IOUtils;
import org.dandsoft.mavrep.data.ArtifactJDO;
import org.dandsoft.mavrep.data.ArtifactName;
import org.dandsoft.mavrep.data.InputStreamResource;
import org.dandsoft.mavrep.data.Resource;

/**
 *
 * @author fin
 */
public class LocalFileSystemArtifactDAOImpl implements ArtifactDAO {

    private static final FileFilter FILE_FILTER = new FileFilter() {

        @Override
        public boolean accept(File pathname) {
            return pathname.isFile();
        }
    };
    private static final FileFilter DIRECTORY_FILTER = new FileFilter() {

        @Override
        public boolean accept(File pathname) {
            return pathname.isDirectory();
        }
    };
    private File root;
    private boolean isStarted;

    public synchronized void init() {
        root.mkdirs();
        isStarted = true;
    }

    public synchronized void destroy() {
        isStarted = false;
    }

    @Override
    public synchronized void persist(ArtifactJDO artifact) {
        //TODO: should be merging of new and current resources list
        File artifactFolder = getArtifactPath(artifact.getName());
        artifactFolder.mkdirs();
        for (Map.Entry<String, Resource> entry : artifact.getResources().entrySet()) {
            File resourceFile = new File(artifactFolder, entry.getKey());
            try {
                if (entry.getValue() instanceof FileResource) {
                    //check that it is coping of content from one resource to other
                    if (((FileResource) entry.getValue()).getFile().equals(resourceFile)) {
                        continue;
                    }
                }
                storeResource(resourceFile, entry);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public synchronized ArtifactJDO get(ArtifactName artifactName) {
        File artifactFolder = getArtifactPath(artifactName);
        if (!artifactFolder.exists()) {
            return null;
        }
        ArtifactJDO artifact = new ArtifactJDO(artifactName);

        for (File resourceFile : artifactFolder.listFiles(FILE_FILTER)) {
            String resourceName = resourceFile.getName();
            artifact.getResources().put(resourceName, new FileResource(resourceFile));
        }
        return artifact;
    }

    private void storeResource(File resourceFile, Entry<String, Resource> entry) throws IOException {
        FileOutputStream out = null;
        InputStream in = null;
        try {
            out = new FileOutputStream(resourceFile, false);
            in = ((InputStreamResource) entry.getValue()).getInputStream();
            IOUtils.copy(in, out);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
        }
    }

    private StringBuilder convertToStringPath(ArtifactName artifactName) {
        StringBuilder path = new StringBuilder();
        path.append('/').append(artifactName.getGroupId().replace('.', '/'));
        path.append('/').append(artifactName.getArtifactId());
        return path;
    }

    private File getArtifactPath(ArtifactName artifactName) {
        StringBuilder path = convertToStringPath(artifactName);
        if (artifactName.getVersion() != null && artifactName.getVersion().length() > 0) {
            path.append("/").append(artifactName.getVersion());
        }
        return new File(root, path.toString());
    }

    public File getRoot() {
        return root;
    }

    public synchronized void setRoot(File root) {
        if (!isStarted) {
            this.root = root;
        }
    }

    private static class FileResource implements InputStreamResource {

        private File file;

        public FileResource(File file) {
            this.file = file;
        }

        public File getFile() {
            return file;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new FileInputStream(file);
        }

        @Override
        public int getSize() {
            if (file.length() < Integer.MAX_VALUE) {
                return (int) file.length();
            }
            return Integer.MAX_VALUE;
        }
    }

    
}
